//*********************************************************
//
//    Copyright (c) Microsoft. All rights reserved.
//    This code is licensed under the Apache License, Version 2.0.
//    THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
//    ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
//    IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
//    PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//*********************************************************

using System;
using System.Collections.Generic;
using System.Text;
using System.Data.Common;
using System.Xml.Linq;
using System.Collections;
using System.Xml;

namespace Microsoft.Research.DataLayer
{
    public class OPCDataReader : DbDataReader
    {
        private int _index;
        private IEnumerable<XmlNode> _src;
        private List<XmlNode> _rows;
        private int _recordCount;

        private Dictionary<int, string> _fieldNameTable;
        private List<string> _fieldNames;

        public OPCDataReader(IEnumerable<XmlNode> src)
        {
            _index = -1;
            _src = src;
            _recordCount = 0;
            LoadRows();
        }

        private void LoadRows()
        {
            _rows = new List<XmlNode>();

            IEnumerator<XmlNode> srcEnum = _src.GetEnumerator();
            while (srcEnum.MoveNext())
                _rows.Add(srcEnum.Current);

            _recordCount = _rows.Count;
        }

        public IEnumerable<XmlNode> Source { get { return _src; } }

        private XmlNode Current
        {
            get { return (XmlNode)_rows[_index]; }

        }

        private XmlNode CurrentRow()
        {
            if (_rows.Count > 0)
                return _rows[_index];
            else
                return null;
        }

        private XmlNode Field(int index)
        {
            string query = "./" + GetName(index);
            XmlNodeList list = CurrentRow().SelectNodes(query);
            if (list.Count > 0)
                return list[0];
            else
                return null;
        }

        public override void Close()
        {
            /* No action */
        }

        public override int FieldCount
        {
            get
            {
                return _fieldNameTable.Count;
            }
        }

        public override bool GetBoolean(int ordinal)
        {
            return bool.Parse(Field(ordinal).InnerText);
        }

        public override byte GetByte(int ordinal)
        {
            return Convert.ToByte(Field(ordinal).InnerText);
        }

        public override char GetChar(int ordinal)
        {
            return Convert.ToChar(Field(ordinal).InnerText);
        }

        public override DateTime GetDateTime(int ordinal)
        {
            DateTime dateValue;
            if (!DateTime.TryParse(Field(ordinal).InnerText, out dateValue))
                return new DateTime();
            return dateValue;
        }

        public override Guid GetGuid(int ordinal)
        {
            return new Guid(Field(ordinal).InnerText);
        }

        public override short GetInt16(int ordinal)
        {
            return Convert.ToInt16(Field(ordinal).InnerText);
        }

        public override int GetInt32(int ordinal)
        {
            return Convert.ToInt32(Field(ordinal).InnerText);
        }

        public override long GetInt64(int ordinal)
        {
            return Convert.ToInt64(Field(ordinal));
        }

        public override string GetName(int ordinal)
        {
            return _fieldNameTable[ordinal];
        }

        public override int GetOrdinal(string name)
        {
            return _fieldNames.IndexOf(name);
        }

        public override string GetString(int ordinal)
        {
            return Field(ordinal).InnerText;
        }

        public override object GetValue(int ordinal)
        {
            return Field(ordinal).InnerText;
        }

        public override int GetValues(object[] values)
        {
            for (int i = 0; i < values.Length; i++)
            {
                values[i] = Field(i).InnerText;
            }

            return values.Length;
        }

        public override bool HasRows
        {
            get { return _rows.Count > 0; }
        }

        public override bool IsClosed
        {
            get { return false; }
        }

        public override bool IsDBNull(int ordinal)
        {
            return (ordinal == -1 ? true : false);
        }

        private void LoadFieldInfo()
        {
            _fieldNameTable = new Dictionary<int, string>();
            _fieldNames = new List<string>();

            int aux = 0;

            XmlNode row = CurrentRow();

            if (row != null)
            {
                foreach (XmlNode node in row.ChildNodes)
                {
                    _fieldNames.Add(node.Name);
                    _fieldNameTable.Add(aux++, node.Name);
                }
            }
        }

        public override bool NextResult()
        {
            if ((_recordCount == 0) || (_index == _recordCount - 1))
                return false;
            _index++;
            LoadFieldInfo();
            return true;
        }

        public override bool Read()
        {
            return NextResult();
        }

        public override int RecordsAffected
        {
            get { return _recordCount; }
        }

        public override object this[string name]
        {
            get { return GetValue(GetOrdinal(name)); }
        }

        public override object this[int ordinal]
        {
            get { return GetValue(ordinal); }
        }

        #region All NotSupported and Not Implemented

        public override int Depth
        {
            get { throw new NotSupportedException(); }
        }

        public override long GetChars(int ordinal, long dataOffset, char[] buffer, int bufferOffset, int length)
        {
            throw new NotImplementedException();
        }

        public override string GetDataTypeName(int ordinal)
        {
            throw new NotImplementedException();
        }

        public override decimal GetDecimal(int ordinal)
        {
            throw new NotImplementedException();
        }

        public override double GetDouble(int ordinal)
        {
            throw new NotImplementedException();
        }

        public override IEnumerator GetEnumerator()
        {
            throw new NotImplementedException();
        }

        public override System.Type GetFieldType(int ordinal)
        {
            throw new NotSupportedException();
        }

        public override float GetFloat(int ordinal)
        {
            throw new NotImplementedException();
        }

        public override System.Data.DataTable GetSchemaTable()
        {
            throw new NotImplementedException();
        }

        public override long GetBytes(int ordinal, long dataOffset, byte[] buffer, int bufferOffset, int length)
        {
            throw new NotImplementedException();
        }

        #endregion

    }
}
